package com.lehecai.ucenter.action.user;

import com.lehecai.core.YesNoStatus;
import com.lehecai.core.exception.cache.CacheException;
import com.lehecai.core.service.cache.CacheService;
import com.lehecai.core.util.CoreDateUtils;
import com.lehecai.ucenter.action.BaseAction;
import com.lehecai.ucenter.bean.UserSessionBean;
import com.lehecai.ucenter.constant.GlobalConstant;
import com.lehecai.ucenter.entity.permission.User;
import com.lehecai.ucenter.service.permission.UserService;
import com.lehecai.ucenter.utils.GoogleAuthenticator;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.List;

public class OtpAction extends BaseAction {
	private static final long serialVersionUID = -8830679912602886965L;
	
	private UserService userService;
    private CacheService cacheService;
    private String cacheName;

    private String oneTimePassword;

    private User user;
    private String verifyCode;
    private String secretKey;
    private String successMsg;
    private String errorMsg;
    private String now;

	public String handle() {
        UserSessionBean bean = (UserSessionBean)super.getSession().get(GlobalConstant.USER_SESSION_KEY);
        User sUser = bean.getUser();
		user = userService.get(sUser.getId());
        if (user.getOtp().getValue() == YesNoStatus.NO.getValue() && StringUtils.isEmpty(user.getSecretKey())) {
            String secretKey = GoogleAuthenticator.generateSecretKey(user.getPassword());
            user.setSecretKey(secretKey);
            return "register";
        }

		return "view";
	}

    public void showQRCode() {
        HttpServletResponse response = ServletActionContext.getResponse();
        ByteArrayOutputStream outputStream = GoogleAuthenticator.generateLocalQRBarcode(user.getUsername(), "sqbj.com", user.getSecretKey());
        try {
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");

            ServletOutputStream responseOutputStream = response
                    .getOutputStream();
            responseOutputStream.write(outputStream.toByteArray());
            responseOutputStream.flush();
            responseOutputStream.close();
        } catch (Exception e) {
            logger.error("验证码输出失败");
            logger.error(e.getMessage(), e);
        }
    }

    public String register() {
        user = userService.get(user.getId());

        long t = System.currentTimeMillis();
        GoogleAuthenticator ga = new GoogleAuthenticator();
        ga.setWindowSize(5);  //should give 5 * 30 seconds of grace...

        long code = 0L;
        try {
            code = Long.parseLong(verifyCode);
        } catch (NumberFormatException e) {
            logger.error(e.getMessage(), e);
            super.setErrorMessage("6位数字验证码格式不正确");
            return "failure";
        }

        boolean r = ga.check_code(secretKey, code, t);
        if (r) {
            user.setOtp(YesNoStatus.YES);
            user.setUpdatedTime(new Date());
            user.setSecretKey(secretKey);
            userService.update(user);
            successMsg = "验证成功！您已启用动态密码服务，请妥善保管密钥信息！";
            return "view";
        }
        user.setSecretKey(secretKey);
        errorMsg = "6位数字验证码不正确";
        return "register";
    }

    public String change() {
        user = userService.get(user.getId());

        String secretKey = GoogleAuthenticator.generateSecretKey(user.getPassword());
        user.setSecretKey(secretKey);
        return "register";
    }

    public String start() {
        user = userService.get(user.getId());

        if (user.getOtp().getValue() == YesNoStatus.NO.getValue()) {
            String secretKey = GoogleAuthenticator.generateSecretKey(user.getPassword());
            user.setSecretKey(secretKey);
            return "register";
        }
        return "view";
    }

    public String stopVerify() {
        if (StringUtils.isEmpty(oneTimePassword)) {
            logger.error("ucenter登录二次验证oneTimePassword参数为空");
            super.setErrorMessage("ucenter登录二次验证oneTimePassword参数为空");
            return "view";
        }

        user = userService.get(user.getId());

        //验证动态密码
        String cachedOneTimePassword = null;
        try {
            cachedOneTimePassword = cacheService.getObject(String.class, cacheName, oneTimePassword);
        } catch (CacheException e) {
            logger.error("从缓存中读取动态密码出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        if (!StringUtils.isEmpty(cachedOneTimePassword)) {
            String msg = String.format("动态密码已被使用:username=%s, cachedOneTimePassword=%s", user.getUsername(), cachedOneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            return "view";
        }

        long t = System.currentTimeMillis();
        GoogleAuthenticator ga = new GoogleAuthenticator();
        ga.setWindowSize(5);  //should give 5 * 30 seconds of grace...

        long code = 0L;
        try {
            code = Long.parseLong(oneTimePassword);
        } catch (NumberFormatException e) {
            String msg = String.format("动态密码格式不正确，转换成long错误:username=%s, password=%s", user.getUsername(), oneTimePassword);
            logger.error(msg);
            logger.error(e.getMessage(), e);
            super.setErrorMessage(msg);
            return "view";
        }

        boolean r = ga.check_code(user.getSecretKey(), code, t);
        if (!r) {
            String msg = String.format("动态密码不正确:username=%s, otp=%s", user.getUsername(), oneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            return "view";
        }

        try {
            cacheService.setObject(cacheName, oneTimePassword, oneTimePassword);
        } catch (CacheException e) {
            logger.error("设置缓存出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        user.setOtp(YesNoStatus.NO);
        user.setUpdatedTime(new Date());
        userService.update(user);
        return "view";
    }

    public String stop() {
        user = userService.get(user.getId());
        if (user.getOtp().getValue() == YesNoStatus.YES.getValue()) {
            logger.info("用户[{}]已开启动态密码验证", user.getUsername());
            return "stopVerify";
        }
        user.setOtp(YesNoStatus.NO);
        user.setUpdatedTime(new Date());
        userService.update(user);
        return "view";
    }

	public List<YesNoStatus> getYesNoStatusList() {
		return YesNoStatus.getItems();
	}
	
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

    public String getVerifyCode() {
        return verifyCode;
    }

    public void setVerifyCode(String verifyCode) {
        this.verifyCode = verifyCode;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String getSuccessMsg() {
        return successMsg;
    }

    public void setSuccessMsg(String successMsg) {
        this.successMsg = successMsg;
    }

    public String getNow() {
        return CoreDateUtils.formatDateTime(new Date());
    }

    public void setNow(String now) {
        this.now = now;
    }

    public CacheService getCacheService() {
        return cacheService;
    }

    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public String getOneTimePassword() {
        return oneTimePassword;
    }

    public void setOneTimePassword(String oneTimePassword) {
        this.oneTimePassword = oneTimePassword;
    }
}
